package com.favccxx.message.api;


import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.favccxx.message.application.MessageAppService;
import com.favccxx.message.domain.message.MessageProtocol;
import com.favccxx.message.domain.message.entity.endpoint.RabbitmqEndPoint;
import com.favccxx.message.domain.message.entity.process.MessageProcessRule;
import com.favccxx.message.domain.message.entity.router.MessageRouter;
import com.favccxx.message.infrastructure.util.jackson.JacksonUtil;
import com.favccxx.message.infrastructure.util.rest.RestResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;

@RestController
@RequestMapping("/api/v1/msg")
public class MessageController {

    @Autowired
    MessageAppService messageService;

    @PostMapping("/rabbitmq/save")
    public RestResult<RabbitmqEndPoint> create(@RequestParam(value = "url", required = true, defaultValue = "") String url,
                                               @RequestParam(value = "port", required = true, defaultValue = "5672") int port,
                                               @RequestParam(value = "username", required = true, defaultValue = "") String username,
                                               @RequestParam(value = "password", required = true, defaultValue = "") String password,
                                               @RequestParam(value = "version", required = false, defaultValue = "") String version,
                                               @RequestParam(value = "virtualHost", required = false, defaultValue = "/") String virtualHost,
                                               @RequestParam(value = "exchangeName", required = false, defaultValue = "") String exchangeName,
                                               @RequestParam(value = "routingName", required = false, defaultValue = "") String routingName,
                                               @RequestParam(value = "messageType", required = false, defaultValue = "") String messageType,
                                               @RequestParam(value = "queueName", required = false, defaultValue = "") String queueName) {
        RabbitmqEndPoint rabbitmqEndPoint = new RabbitmqEndPoint();
        rabbitmqEndPoint.setUrl(url);
        rabbitmqEndPoint.setPort(port);
        rabbitmqEndPoint.setUsername(username);
        rabbitmqEndPoint.setPassword(password);
        rabbitmqEndPoint.setVersion(version);
        rabbitmqEndPoint.setVirtualHost(virtualHost);
        rabbitmqEndPoint.setType(MessageProtocol.RABBITMQ.getName());
        rabbitmqEndPoint.setExchangeName(exchangeName);
        rabbitmqEndPoint.setRoutingName(routingName);
        rabbitmqEndPoint.setMessageType(messageType);
        rabbitmqEndPoint.setQueueName(queueName);
        rabbitmqEndPoint.setCreateTime(LocalDateTime.now());
        rabbitmqEndPoint.setUpdateTime(LocalDateTime.now());

        messageService.saveRabbitMQ(rabbitmqEndPoint);
        return RestResult.sucess(rabbitmqEndPoint);
    }


    @PostMapping("/router/save")
    public RestResult<MessageRouter> saveRouter(@RequestParam(value = "routerName", required = true, defaultValue = "") String routerName,
                                                @RequestParam(value = "messageFormat", required = true, defaultValue = "JSON") String messageFormat,
                                                @RequestParam(value = "fromEndPoint", required = true, defaultValue = "") String fromEndPoint,
                                                @RequestParam(value = "toEndPoint", required = true, defaultValue = "") String toEndPoint,
                                                @RequestParam(value = "filterInstance", required = false, defaultValue = "") String filterInstance,
                                                @RequestParam(value = "preprocessor", required = false, defaultValue = "") String preprocessor,
                                                @RequestParam(value = "persistence", required = false, defaultValue = "false") boolean persistence,
                                                @RequestParam(value = "processor", required = false, defaultValue = "") String processor,
                                                @RequestParam(value = "status", required = false, defaultValue = "true") boolean status) {
        MessageRouter messageRouter = new MessageRouter();
        messageRouter.setRouterName(routerName);
        messageRouter.setMessageFormat(messageFormat);
        messageRouter.setFromEndPoint(fromEndPoint);
        messageRouter.setToEndPoint(toEndPoint);
        messageRouter.setFilterInstance(filterInstance);
        messageRouter.setPreprocessor(preprocessor);
        messageRouter.setPersistence(persistence);
        messageRouter.setProcessor(processor);
        messageRouter.setStatus(status);
        messageRouter.setCreateTime(LocalDateTime.now());
        messageRouter.setUpdateTime(LocalDateTime.now());

        messageService.saveMessageRouter(messageRouter);
        return RestResult.sucess(messageRouter);
    }


    @PostMapping("/router/updateRule")
    public RestResult updateProcessRule(@RequestParam(value = "routerId", required = true, defaultValue = "") String routerId,
                                        @RequestParam(value = "preprocessor", required = false, defaultValue = "") String preprocessor,
                                        @RequestParam(value = "preProcessRules", required = false, defaultValue = "") String preProcessRules,
                                        @RequestParam(value = "processor", required = false, defaultValue = "") String processor,
                                        @RequestParam(value = "processRules", required = false, defaultValue = "") String processRules) {
        MessageRouter messageRouter = messageService.findById(routerId);
        if (messageRouter == null) {
            return RestResult.error(1001, "Could not update message router, because the routerId is invalid.");
        }

        if (StringUtils.isBlank(preprocessor) && StringUtils.isNoneBlank(preProcessRules)) {
            return RestResult.error(1002, "Could not update message router, PreprocessRules must work with preprocessor.");
        }

        if (StringUtils.isBlank(processor) && StringUtils.isNoneBlank(processRules)) {
            return RestResult.error(1003, "Could not update message router, processRules must work with processor.");
        }


        if (StringUtils.isNoneBlank(preProcessRules)) {
            try {
                MessageProcessRule preProcessRule = JacksonUtil.jsonToObject(preProcessRules, MessageProcessRule.class);
                preProcessRule.setLevel("PREPROCESS");

                messageRouter.setPreprocessor(preprocessor);
                messageRouter.setPreProcessRules(JacksonUtil.toJsonString(preProcessRule));

            } catch (Exception e) {
                e.printStackTrace();
                return RestResult.error(1004, "Could not update message router, preProcessRules invalid.");
            }
        }


        if (StringUtils.isNoneBlank(processRules)) {
            try {
                MessageProcessRule messageProcessRule = JacksonUtil.jsonToObject(processRules, MessageProcessRule.class);
                messageProcessRule.setLevel("PROCESS");

                messageRouter.setProcessor(processor);
                messageRouter.setProcessRules(JacksonUtil.toJsonString(messageProcessRule));
            } catch (Exception e) {
                e.printStackTrace();
                return RestResult.error(1005, "Could not update message router, ProcessRules invalid.");
            }
        }


        messageRouter.setUpdateTime(LocalDateTime.now());
        messageService.saveMessageRouter(messageRouter);
        return RestResult.sucess(messageRouter);
    }

    public static JavaType getCollectionType(ObjectMapper mapper, Class<?> collectionClass, Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }


}
